package com.ruoyi.common.utils;


import org.apache.commons.lang3.BooleanUtils;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

public class RandomUtil {

  private static final Random RANDOM = new Random();

  /**
   * 用于随机选的数字
   */
  private static final String BASE_NUMBER = "0123456789";
  /**
   * 用于随机选的字符
   */
  private static final String BASE_CHAR = "abcdefghijklmnopqrstuvwxyz";
  /**
   * 用于随机选的字符和数字
   */
  private static final String BASE_CHAR_NUMBER = BASE_CHAR + BASE_NUMBER;

  public RandomUtil() {
  }

  public static String getRandomStr() {
    return getRandomStr(16);
  }

  public static String getRandomStr(Integer length) {
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < length; ++i) {
      sb.append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(RANDOM.nextInt("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".length())));
    }

    return sb.toString();
  }

  public static String getRandomNumStr(Integer length) {
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < length; ++i) {
      sb.append("0123456789".charAt(RANDOM.nextInt("0123456789".length())));
    }
    return sb.toString();
  }

  public static Long getRandomNum(Integer length) {
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < length; ++i) {
      sb.append("0123456789".charAt(RANDOM.nextInt("0123456789".length())));
    }
    return Long.parseLong(sb.toString());
  }

  public static Integer getRandomInteger(Integer min, Integer max){
    min = min != null ? min: 0;
    max = max != null ? max: 0;
    if(min > max) {
      return null;
    }
    return (int)Math.round(Math.random()*(max-min) + min);
  }

  public static Long getRandomLong(Long min, Long max){
    min = min != null ? min: 0;
    max = max != null ? max: 0;
    if(min > max) {
      return null;
    }
    return Math.round(Math.random()*(max-min) + min);
  }

  /**
   * 获取随机数生成器对象
   * ThreadLocalRandom是JDK 7之后提供并发产生随机数，能够解决多个线程发生的竞争争夺
   */
  public static ThreadLocalRandom getRandom() {
    return ThreadLocalRandom.current();
  }

  /**
   * 获得指定范围内的随机数
   *
   * @param min 最小数（包含）
   * @param max 最大数（不包含）
   */
  public static int randomInt(int min, int max) {
    return getRandom().nextInt(min, max);
  }

  /**
   * 获得随机数[0, 2^32)
   */
  public static int randomInt() {
    return getRandom().nextInt();
  }

  /**
   * 获得指定范围内的随机数 [0,limit)
   *
   * @param limit 限制随机数的范围，不包括这个数
   */
  public static int randomInt(int limit) {
    return getRandom().nextInt(limit);
  }

  /**
   * 获得指定范围内的随机数[min, max)
   *
   * @param min 最小数（包含）
   * @param max 最大数（不包含）
   */
  public static long randomLong(long min, long max) {
    return getRandom().nextLong(min, max);
  }

  /**
   * 获得随机数
   */
  public static long randomLong() {
    return getRandom().nextLong();
  }

  /**
   * 获得指定范围内的随机数 [0,limit)
   *
   * @param limit 限制随机数的范围，不包括这个数
   */
  public static long randomLong(long limit) {
    return getRandom().nextLong(limit);
  }

  /**
   * 获得指定范围内的随机数
   *
   * @param min 最小数（包含）
   * @param max 最大数（不包含）
   */
  public static double randomDouble(double min, double max) {
    return getRandom().nextDouble(min, max);
  }

  /**
   * 获得随机数[0, 1)
   */
  public static double randomDouble() {
    return getRandom().nextDouble();
  }

  /**
   * 获得指定范围内的随机数 [0,limit)
   *
   * @param limit 限制随机数的范围，不包括这个数
   */
  public static double randomDouble(double limit) {
    return getRandom().nextDouble(limit);
  }

  /**
   * 随机bytes
   *
   * @param length 长度
   */
  public static byte[] randomBytes(int length) {
    byte[] bytes = new byte[length];
    getRandom().nextBytes(bytes);
    return bytes;
  }


  /**
   * 获得一个随机的字符串（只包含数字和字符）
   *
   * @param length 字符串的长度
   */
  public static String randomString(int length) {
    return randomString(BASE_CHAR_NUMBER, length);
  }

  /**
   * 获得一个只包含数字的字符串
   *
   * @param length 字符串的长度
   */
  public static String randomNumbers(int length) {
    return randomString(BASE_NUMBER, length);
  }

  /**
   * 获得一个随机的字符串
   *
   * @param baseString 随机字符选取的样本
   * @param length     字符串的长度
   */
  public static String randomString(String baseString, int length) {

    final StringBuilder sb = new StringBuilder(length);

    if (length < 1) {
      length = 1;
    }
    int baseLength = baseString.length();
    for (int i = 0; i < length; i++) {
      int number = randomInt(baseLength);
      sb.append(baseString.charAt(number));
    }
    return sb.toString();
  }


  public static List<Integer> getRandomNum(Integer length, List<Integer> exclude, Integer startWith, Boolean repeatable, Integer repeatNum){
    List result = new ArrayList(length);
    while (result.size() < length) {
      Integer r = getRandomNum(1).intValue();
      if(startWith != null && (result.size() == 0 && r != startWith)) {
        continue;
      }
      if(exclude.contains(r.intValue())) {
        continue;
      }
      result.add(r);
    }
    Set<Integer> tmp = new HashSet<>(result);
    if(BooleanUtils.isTrue(repeatable)) {
      // 默认可重复2个数字
      repeatNum = repeatNum != null ? repeatNum: 2;
      if(length - tmp.size() != repeatNum -1) { // 5 - 4 != 1
        return getRandomNum(length, exclude, startWith, repeatable, repeatNum);
      }
    }else {
      if(tmp.size() != length) {
        return getRandomNum(length, exclude, startWith, repeatable, repeatNum);
      }
    }
    return result;
  }

}
